package ch.elca.lol.puissance4.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

import ch.elca.lol.puissance4.board.Board;
import ch.elca.lol.puissance4.board.FastImBoard;
import ch.elca.lol.puissance4.game.Token;

/** Static helper methods, mainly for AI implementors. */
public class Util {
	public static boolean debug = false;
	
	public static void debugPrintArray(String mess, int[] scores) {
		if(debug) {
			System.out.print(mess + ":\t");
			for(int v : scores) {
				System.out.print(v + "\t");
			}
			System.out.println();
		}
	}
	
	private static final Scanner scanner = new Scanner(System.in);
	
	public static String stdinNextLine() {
		return scanner.nextLine();
	}
	
	public static int stdinNextInt() {
		return scanner.nextInt();
	}
	
	/**
	 * Sames as maxIndex except that in case there are multiple indices with the same maximal value, one
	 * is chosen at random.
	 */
	public static int maxIndexRandom(int... vals) {
		int maxVal = max(vals);
		ArrayList<Integer> legal = new ArrayList<Integer>(vals.length);
		for(int c = 0; c < vals.length; c++) {
			if(vals[c] == maxVal)
				legal.add(c);
		}
		
		Collections.shuffle(legal);
		return legal.get(0);
	}
	
	/** Returns the index whose value is the largest. In case of equality the earlier index is returned. */
	public static int maxIndex(int... vals) {
		int col = -1;
		int best = Integer.MIN_VALUE;
		
		for(int c = 0; c < vals.length; c++) {
			int score = vals[c];
			if(score > best) {
				best = score;
				col = c;
			}
		}
		
		return col;
	}
	
	public static int max(int a, int b) {
		return (a < b) ? b : a; 
	}

	public static int min(int a, int b) {
		return (a > b) ? b : a; 
	}

	public static int max(int... vals) {
		// Keep only the best score
		int best = Integer.MIN_VALUE;
		
		for(int score : vals) {
			if(score > best) {
				best = score;
			}
		}
		
		return best;
	}
	
	public static int min(int ... vals) {
		int worst = Integer.MAX_VALUE;
		
		for(int score : vals) {
			if(score < worst) {
				worst = score;
			}
		}
		
		return worst;
	}
	
	/** Random value between min included and max excluded. */
	public static int random(int min, int max) {
		return min + (int) (Math.random() * (max - min));
	}
	
	public static Board fromString(String s, int w, int h) {
		Board b = new FastImBoard(w, h);
		
		char[] chars = s.toCharArray();
		for(int y = 0; y < h; y++) {
			for(int x = 0; x < w; x++) {
				char c = chars[x + (h - y - 1) * (w + 1)];
				Token t = Token.fromChar(c);
				if(t != null)
					b = b.play(x, t);
			}
		}
		
		return b;
	}
	
	/** Prints the board has a matrix of characters, X and O for played squares and . for empty ones. */
	public static String boardToString(Board b) {
		StringBuilder sb = new StringBuilder();
		Token s;
		
		int h = b.getHeight();
		int w = b.getWidth();
		
		for(int y = h - 1; y >= 0; y--) { // Lines from top to bottom
			for(int x = 0; x < w; x++) { // Columns from left to right
				s = b.unsafeGet(x, y);
				if(s == null)
					sb.append(".");
				else
					sb.append(s);
			}
			sb.append("\n");
		}
		
		for(int x = 0; x < w; x++) {
			sb.append("-");
		}
		sb.append("\n");
		for(int x = 0; x < w; x++) {
			sb.append(x + 1);
		}
		
		return sb.toString();
	}
	
	public static Iterable<Integer> possiblePlays(Board b) {
		ArrayList<Integer> plays = new ArrayList<Integer>();
		
		for(int col = 0; col < b.getWidth(); col++) {
			if(b.isPlayable(col))
				plays.add(col);
		}
		
		return plays;
	}
}
